package com.longrise.fileuploader;

import android.content.Context;
import android.os.Handler;
import android.os.Looper;

import com.google.gson.Gson;
import com.longrise.fileuploader.body.ProgressRequestBody;
import com.longrise.fileuploader.response.GsonResponseHandler;
import com.longrise.fileuploader.response.IResponseHandler;
import com.longrise.fileuploader.response.JsonResponseHandler;
import com.longrise.fileuploader.response.RawResponseHandler;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.File;
import java.io.IOException;
import java.net.FileNameMap;
import java.net.URLConnection;
import java.util.Map;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by xkj on 17/4/5.
 * BBOkHttp
 */
public class BBOkHttp {

    private OkHttpClient client;
    private static BBOkHttp instance;
    private Context mContext;
    private static String mAppVersion;
    private static String mToken;
    private static String mBbuuid;

    private BBOkHttp() {

    }

    private BBOkHttp(Context context) {
        this.mContext = context;
        client = new OkHttpClient.Builder()
                .build();
    }

    /**
     * @return
     */
    public static BBOkHttp getInstance(Context context, String appVersion, String token, String byjkuuid) {
        if (instance == null) {
            instance = new BBOkHttp(context);
            mAppVersion = appVersion;
            mToken = token;
            mBbuuid = byjkuuid;
        }
        return instance;
    }

    /**
     * 上传文件
     *
     * @param url             url
     * @param files           上传的文件files
     * @param responseHandler 回调
     */
    public void upload(String url, Map<String, File> files, final IResponseHandler responseHandler) {
        upload(null, url, null, files, responseHandler);
    }

    /**
     * 上传文件
     *
     * @param url             url
     * @param params          参数
     * @param files           上传的文件files
     * @param responseHandler 回调
     */
    public void upload(String url, Map<String, String> params, Map<String, File> files, final IResponseHandler responseHandler) {
        upload(null, url, params, files, responseHandler);
    }

    /**
     * 上传文件
     *
     * @param context         发起请求的context
     * @param url             url
     * @param files           上传的文件files
     * @param responseHandler 回调
     */
    public void upload(Context context, String url, Map<String, File> files, final IResponseHandler responseHandler) {
        upload(context, url, null, files, responseHandler);
    }

    /**
     * 上传文件
     *
     * @param context         发起请求的context
     * @param url             url
     * @param params          参数
     * @param files           上传的文件files
     * @param responseHandler 回调
     */
    public void upload(Context context, String url, Map<String, String> params, Map<String, File> files, final IResponseHandler responseHandler) {
        MultipartBody.Builder multipartBuilder = new MultipartBody.Builder().setType(MultipartBody.FORM);

        //添加参数
        if (params != null && !params.isEmpty()) {
            for (String key : params.keySet()) {
                multipartBuilder.addFormDataPart(key, params.get(key));
            }
        }

        //添加上传文件
        if (files != null && !files.isEmpty()) {
            RequestBody fileBody;
            for (String key : files.keySet()) {
                File file = files.get(key);
                String fileName = file.getName();
                fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                multipartBuilder.addFormDataPart(key, fileName, fileBody);
            }
        }

        Request.Builder builder;
        if (context == null) {
            builder = new Request.Builder()
                    .url(url)
                    .addHeader("App-Version", mAppVersion)
                    .addHeader("Accept-Encoding", "gzip")
                    .addHeader("OSType", "android")
                    .addHeader("apptoken", mToken)
                    .addHeader("bbkey", mBbuuid)
                    .post(new ProgressRequestBody(new Handler(), multipartBuilder.build(), responseHandler));
        } else {
            builder = new Request.Builder()
                    .url(url)
                    .addHeader("App-Version", mAppVersion)
                    .addHeader("Accept-Encoding", "gzip")
                    .addHeader("OSType", "android")
                    .addHeader("apptoken", mToken)
                    .addHeader("bbkey", mBbuuid)
                    .post(new ProgressRequestBody(new Handler(), multipartBuilder.build(), responseHandler))
                    .tag(context);
        }
        Request request = builder.build();

        client.newCall(request).enqueue(new MyCallback(new Handler(), responseHandler));
    }


    /**
     * 取消当前context的所有请求
     *
     * @param context
     */
    public void cancel(Context context) {
        if (client != null) {
            for (Call call : client.dispatcher().queuedCalls()) {
                if (call.request().tag().equals(context))
                    call.cancel();
            }
            for (Call call : client.dispatcher().runningCalls()) {
                if (call.request().tag().equals(context))
                    call.cancel();
            }
        }
    }


    //callback
    private class MyCallback implements Callback {

        private Handler mHandler;
        private IResponseHandler mResponseHandler;

        public MyCallback(Handler handler, IResponseHandler responseHandler) {
            mHandler = handler;
            mResponseHandler = responseHandler;
        }

        @Override
        public void onFailure(Call call, final IOException e) {

            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    mResponseHandler.onFailure(0, e.toString());
                }
            });
        }

        @Override
        public void onResponse(Call call, final Response response) throws IOException {
            if (response.isSuccessful()) {
                final String response_body = response.body().string();

                if (mResponseHandler instanceof JsonResponseHandler) {       //json回调
                    try {
                        final JSONObject jsonBody = new JSONObject(response_body);
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                ((JsonResponseHandler) mResponseHandler).onSuccess(response.code(), jsonBody);
                            }
                        });
                    } catch (JSONException e) {
                        mHandler.post(new Runnable() {
                            @Override
                            public void run() {
                                mResponseHandler.onFailure(response.code(), "fail parse jsonobject, body=" + response_body);
                            }
                        });
                    }
                } else if (mResponseHandler instanceof GsonResponseHandler) {    //gson回调
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                Gson gson = new Gson();
                                ((GsonResponseHandler) mResponseHandler).onSuccess(response.code(),
                                        gson.fromJson(response_body, ((GsonResponseHandler) mResponseHandler).getType()));
                            } catch (Exception e) {
                                mResponseHandler.onFailure(response.code(), "fail parse gson, body=" + response_body);
                            }

                        }
                    });
                } else if (mResponseHandler instanceof RawResponseHandler) {     //raw字符串回调
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            ((RawResponseHandler) mResponseHandler).onSuccess(response.code(), response_body);
                        }
                    });
                }
            } else {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        mResponseHandler.onFailure(0, "fail status=" + response.code());
                    }
                });
            }
        }
    }


    //获取mime type
    private String guessMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }
}

